//
//  VerifyViewModel.swift
//  App_Login
//
//  Created by 蒋晨成 on 2022/1/4.
//

import App_Common
import Center
import RxCocoa
import RxSwift
import UICore
import UIKit

class VerifyViewModel: ViewModel, ViewModelType {
    private let code = PublishSubject<String>()
    private let mobile = BehaviorRelay<String>(value: RegisterCenter.mobile ?? "")
    private let submitState = PublishSubject<HandleState>()
    private var disposeBag = DisposeBag()
    private var lastCode: String = ""
}

extension VerifyViewModel {
    struct Input {
        let code: Driver<String>
        let sendSMSTap: Observable<Bool>
    }

    struct Output {
        let mobile: Observable<String>
        let code: Observable<String?>
        let timer: Observable<Int>
        let submitState: Driver<HandleState>
    }

    func transform(input: Input) -> Output {
        let code = handleCode(input.code)
        let timer = handleSendSMSTap(input.sendSMSTap)
        return Output(
            mobile: mobile.asObservable(),
            code: code,
            timer: timer,
            submitState: submitState.asDriver(onErrorJustReturn: .failure(message: LoginModular.localizedString(key: "Verify.System.Error")))
        )
    }
}

private extension VerifyViewModel {
    func handleCode(_ observe: Driver<String>) -> Observable<String?> {
        observe.asObservable()
            .map { [weak self] code in
                guard code.count >= 4 else { return code }
                let value = code.slicing(from: 0, length: 4)
                self?.sendCode(code: value)
                return value
            }
            .asObservable()
    }

    func handleSendSMSTap(_ observe: Observable<Bool>) -> Observable<Int> {
        observe.asObservable()
            .flatMapLatest { [weak self] isSend -> Observable<Int> in
                if isSend { self?.sendSMS() }
                return Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
            }
            .asObservable()
    }

    func sendCode(code: String?) {
        guard let mobile = RegisterCenter.mobile else {
            submitState.onNext(.failure(message: LoginModular.localizedString(key: "Verify.Mobile.Empty")))
            return
        }
        guard let code = code, lastCode != code else { return }
        lastCode = code
        submitState.onNext(.doing)
        UserCenter.Sign.Mobile.auth(mobile: mobile, code: code) { [weak self] result in
            switch result {
            case .success:
                self?.submitState.onNext(.success)
            case .failure(let error):
                self?.submitState.onNext(.failure(message: error.localizedDescription))
            }
        }
    }

    func sendSMS() {
        guard let mobile = RegisterCenter.mobile else {
            submitState.onNext(.failure(message: LoginModular.localizedString(key: "Verify.Mobile.Empty")))
            return
        }

        let now = Date()
        guard now.timeIntervalSince1970 > RegisterCenter.expireIn?.timeIntervalSince1970 ?? 0 else {
            submitState.onNext(.failure(message: LoginModular.localizedString(key: "Verify.SMS.Frequently")))
            return
        }
        RegisterCenter.expireIn = now.addingTimeInterval(60)
        UserCenter.Sign.Mobile.sendSMS(mobile: mobile) { [weak self] result in
            switch result {
            case .success: break
            case .failure(let error):
                self?.submitState.onNext(.failure(message: error.localizedDescription))
            }
        }
        UserCenter.loginType = .apple
    }
}
